package com.blog4j.article.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.thread.ThreadUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.blog4j.api.vo.UserInfoVo;
import com.blog4j.article.component.ApiCallService;
import com.blog4j.article.component.AsyncService;
import com.blog4j.article.entity.ArticleEntity;
import com.blog4j.article.entity.CommentEntity;
import com.blog4j.article.entity.ArticleVerifyRecordEntity;
import com.blog4j.article.mapper.ArticleMapper;
import com.blog4j.article.mapper.CommentMapper;
import com.blog4j.article.mapper.ArticleVerifyRecordMapper;
import com.blog4j.article.model.Comment;
import com.blog4j.article.model.CommentUser;
import com.blog4j.article.service.CommentService;
import com.blog4j.article.vo.req.CommentReqVo;
import com.blog4j.article.vo.req.SendCommentReqVo;
import com.blog4j.common.constants.CommonConstant;
import com.blog4j.common.enums.ArticleVerifyContentTypeEnum;
import com.blog4j.common.enums.ErrorEnum;
import com.blog4j.common.enums.VerifyStatusEnum;
import com.blog4j.common.enums.YesOrNoEnum;
import com.blog4j.common.exception.Blog4jException;
import com.blog4j.common.utils.CommonUtil;
import com.blog4j.contentVerify.context.ContentVerifyContext;
import com.blog4j.contentVerify.context.VerifyResult;
import com.blog4j.contentVerify.enums.TextServiceEnum;
import com.blog4j.contentVerify.enums.VerifyResultEnum;
import com.blog4j.contentVerify.enums.VerifyTypeEnum;
import com.blog4j.contentVerify.model.TextVerifyModel;
import com.blog4j.contentVerify.processor.VerifyProcessor;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author 98k灬
 * @version v1.0.0
 * @Description : 功能描述
 * @Create on : 2024/7/28 20:54
 **/
@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class CommentServiceImpl extends ServiceImpl<CommentMapper, CommentEntity>
        implements CommentService {
    private final ArticleMapper articleMapper;
    private final VerifyProcessor verifyProcessor;
    private final ArticleVerifyRecordMapper articleVerifyRecordMapper;
    private final AsyncService asyncService;
    private final ApiCallService apiCallService;

    /**
     * 获取文章评论列表
     *
     * @param reqVo 请求信息
     * @return 评论列表
     */
    @Override
    public PageInfo<Comment> commentList(CommentReqVo reqVo) {
        Integer pageSize = reqVo.getPageSize();
        Integer pageNo = reqVo.getPageNo();
        String articleId = reqVo.getArticleId();
        ArticleEntity article = articleMapper.selectById(articleId);
        if (Objects.isNull(article)) {
            throw new Blog4jException(ErrorEnum.ARTICLE_NOT_EXIST_ERROR);
        }

        LambdaQueryWrapper<CommentEntity> wrapper = new LambdaQueryWrapper<CommentEntity>()
                .eq(CommentEntity::getArticleId, articleId)
                .orderByDesc(CommentEntity::getCreateTime);
        Page<Object> page = PageHelper.startPage(pageNo, pageSize);
        List<CommentEntity> commentEntityList = this.baseMapper.selectList(wrapper);
        if (CollectionUtil.isEmpty(commentEntityList)) {
            return new PageInfo<>();
        }

        List<Comment> commentList = commentEntityList.stream().map(item -> {
            Comment comment = Comment.builder()
                    .parentId(item.getParentId())
                    .id(item.getCommentId())
                    .content(item.getContent())
                    .createDate(item.getCreateTime())
                    .build();

            String commentUserId = item.getCommentUserId();
            UserInfoVo commentUserInfo = apiCallService.getUserInfoByUserId(commentUserId);
            CommentUser commentUser = CommentUser.builder()
                    .id(commentUserInfo.getId())
                    .nickName(commentUserInfo.getUserName())
                    .avatar(commentUserInfo.getAvatar())
                    .build();

            String targetUserId = item.getTargetUserId();
            CommentUser targetUser = new CommentUser();
            if (StringUtils.isNotBlank(targetUserId)) {
                UserInfoVo targetUserInfo = apiCallService.getUserInfoByUserId(targetUserId);
                targetUser = CommentUser.builder()
                        .id(targetUserInfo.getId())
                        .nickName(targetUserInfo.getUserName())
                        .avatar(targetUserInfo.getAvatar())
                        .build();
            }
            comment.setCommentUser(commentUser).setTargetUser(targetUser);
            return comment;
        }).collect(Collectors.toList());

        List<Comment> list = new ArrayList<>();
        for (Comment entity : commentList) {
            if (Objects.equals(entity.getParentId(), 0)) {
                list.add(entity);
            }
        }

        for (Comment entity : list) {
            childrenMenu(commentList, entity);
        }

        PageInfo<Comment> pageInfo = new PageInfo<>(list);
        pageInfo.setTotal(page.getTotal());
        return pageInfo;
    }

    /**
     * 给文章评论
     *
     * @param reqVo 评论信息
     */
    @Override
    public void sendComment(SendCommentReqVo reqVo) {
        String content = reqVo.getContent();
        Integer parentId = reqVo.getParentId();
        String commentUserId = reqVo.getCommentUserId();
        Integer targetUserId = reqVo.getTargetUserId();
        String articleId = reqVo.getArticleId();

        String userId = StpUtil.getLoginIdAsString();

        if (!checkCommentContent(content, userId)) {
            asyncService.addUserIllegalRecord(userId);
            throw new Blog4jException(ErrorEnum.COMMENT_CONTENT_ILLEGAL_ERROR);
        }

        if (!StringUtils.equals(userId, commentUserId)) {
            throw new Blog4jException(ErrorEnum.INVALID_PARAMETER_ERROR);
        }

        UserInfoVo userInfoVo = apiCallService.getUserInfoByUserId(userId);
        if (StringUtils.isBlank(userInfoVo.getUserId())) {
            throw new Blog4jException(ErrorEnum.USER_NOT_EXIST_ERROR);
        }

        if (Objects.equals(userInfoVo.getSpeakStatus(), YesOrNoEnum.NO.getCode())) {
            throw new Blog4jException(ErrorEnum.USER_NOT_ALLOW_COMMENT);
        }

        UserInfoVo commentUser = apiCallService.getUserInfoByUserId(commentUserId);
        if (Objects.isNull(commentUser)) {
            throw new Blog4jException(ErrorEnum.USER_NOT_EXIST_ERROR);
        }

        ArticleEntity article = articleMapper.selectById(articleId);
        if (Objects.isNull(article)) {
            throw new Blog4jException(ErrorEnum.ARTICLE_NOT_EXIST_ERROR);
        }

        if (Objects.equals(article.getAllowComment(), YesOrNoEnum.NO.getCode())) {
            throw new Blog4jException(ErrorEnum.APPROVE_NOT_ALLOW_COMMENT_ERROR);
        }

        if (Objects.equals(YesOrNoEnum.NO.getCode(), parentId)) {
            CommentEntity commentEntity = CommentEntity.builder()
                    .parentId(parentId)
                    .articleId(articleId)
                    .content(content)
                    .commentUserId(commentUserId)
                    .deleted(YesOrNoEnum.NO.getCode())
                    .createTime(CommonUtil.getCurrentDateTime())
                    .build();
            this.baseMapper.insert(commentEntity);
        } else {
            if (Objects.isNull(targetUserId)) {
                throw new Blog4jException(ErrorEnum.INVALID_PARAMETER_ERROR);
            }

            UserInfoVo targetUser = apiCallService.getUserInfoById(targetUserId);
            if (Objects.isNull(targetUser)) {
                throw new Blog4jException(ErrorEnum.USER_NOT_EXIST_ERROR);
            }

            CommentEntity commentEntity = CommentEntity.builder()
                    .parentId(parentId)
                    .articleId(articleId)
                    .content(content)
                    .commentUserId(commentUserId)
                    .targetUserId(targetUser.getUserId())
                    .deleted(YesOrNoEnum.NO.getCode())
                    .createTime(CommonUtil.getCurrentDateTime())
                    .build();
            this.baseMapper.insert(commentEntity);
        }
    }

    private Comment childrenMenu(List<Comment> menuList, Comment menu) {
        List<Comment> children = new ArrayList<>();
        for (Comment m : menuList) {
            if (Objects.equals(m.getParentId(), menu.getId())) {
                children.add(childrenMenu(menuList, m));
            }
        }
        menu.setChildrenList(children);
        return menu;
    }

    /**
     * 评论内容风险检测
     *
     * @param commentContent 评论内容
     */
    public boolean checkCommentContent(String commentContent, String userId) {
        boolean checkResult = Boolean.TRUE;
        if (StringUtils.isBlank(commentContent) || StringUtils.isBlank(userId)) {
            return true;
        }
        VerifyResult verifyResult = this.getCommentContentVerifyResult(commentContent);
        // 获取阿里云内容审核接口失败 重试三次
        if (!verifyResult.getStatus()) {
            try {
                int retryTime = 0;
                while(retryTime < CommonConstant.DEFAULT_RETRY_TIMES) {
                    verifyResult = this.getCommentContentVerifyResult(commentContent);
                    if (verifyResult.getStatus()) {
                        break;
                    }
                    ThreadUtil.sleep(CommonConstant.DEFAULT_RETRY_INTERVAL_TIME);
                    retryTime += 1;
                }

                if (!verifyResult.getStatus()) {
                    // 重试了三次还是调用失败
                    ArticleVerifyRecordEntity commentVerifyRecord = new ArticleVerifyRecordEntity();
                    commentVerifyRecord.setVerifyContent(commentContent)
                            .setContentType(ArticleVerifyContentTypeEnum.ARTICLE_COMMENT.getType())
                            .setUserId(userId)
                            .setNeedManualVerify(YesOrNoEnum.YES.getCode())
                            .setVerifyStatus(VerifyStatusEnum.WAIT.getStatus());
                    articleVerifyRecordMapper.insert(commentVerifyRecord);
                    return true;
                }
            } catch (Exception exception) {
                log.error("checkCommentContent error .");
                throw new Blog4jException(ErrorEnum.SYSTEM_ERROR);
            }
        }

        VerifyResultEnum result = verifyResult.getResult();
        if (result == VerifyResultEnum.PASS) {
            return Boolean.TRUE;
        }
        ArticleVerifyRecordEntity commentVerifyRecord = new ArticleVerifyRecordEntity();
        commentVerifyRecord.setVerifyContent(commentContent)
                .setContentType(ArticleVerifyContentTypeEnum.ARTICLE_COMMENT.getType())
                .setUserId(userId)
                .setVerifyStatus(VerifyStatusEnum.VERIFIED.getStatus())
                .setVerifyType(com.blog4j.common.enums.VerifyTypeEnum.MACHINE.getType())
                .setNeedManualVerify(YesOrNoEnum.NO.getCode())
                .setVerifyTime(CommonUtil.getCurrentDateTime());
        if (result == VerifyResultEnum.IN_DOUBT) {
            // 审核存疑
            commentVerifyRecord.setVerifyStatus(VerifyStatusEnum.WAIT.getStatus())
                    .setVerifyResult(VerifyResultEnum.IN_DOUBT.getDesc())
                    .setNeedManualVerify(YesOrNoEnum.YES.getCode());
        } else if (result == VerifyResultEnum.REJECT) {
            // 审核拒绝
            commentVerifyRecord.setVerifyResult(VerifyResultEnum.REJECT.getDesc())
                    .setRiskLevel(verifyResult.getRiskLevel())
                    .setRiskTips(verifyResult.getRiskTips())
                    .setRiskWords(verifyResult.getRiskWords())
                    .setRiskLabel(verifyResult.getLabels());
            checkResult = Boolean.FALSE;
        }
        articleVerifyRecordMapper.insert(commentVerifyRecord);
        return checkResult;
    }

    private VerifyResult getCommentContentVerifyResult(String commentContent) {
        TextVerifyModel textVerifyModel = new TextVerifyModel();
        textVerifyModel.setTextContent(commentContent);
        textVerifyModel.setTextService(TextServiceEnum.COMMENT_DETECTION.getService());
        ContentVerifyContext verifyContext = ContentVerifyContext.builder()
                .verifyType(VerifyTypeEnum.TEXT)
                .textVerifyModel(textVerifyModel)
                .build();
        verifyProcessor.contentVerify(verifyContext);
        return verifyContext.getVerifyResult();
    }
}
